package net.retorx

import java.util.Date
import net.retorx.util.ImageUtil._
import net.retorx.jai.ImageFileManager._
import com.google.inject.name.Named
import java.util.Properties
import collection.JavaConversions._
import java.io.{FileWriter, FileInputStream, File}
import java.text.SimpleDateFormat
import com.google.inject.{Inject, Singleton}
import org.apache.commons.io.FileUtils

@Singleton
class ImageContentBuilder @Inject() (@Named("content.dir") contentDir:File) {

    def getImagesFromContentDir = {
        if ( ! contentDir.exists) {
            throw new IllegalStateException("No such directory: " + contentDir.getAbsolutePath)
        }

        val images = new collection.mutable.ListBuffer[ImageContent]
        contentDir.listFiles.foreach(file => {
            buildImageContent(file) match {
                case Some(imageContent) => images += imageContent
                case None =>
            }

        })

        images
    }

    def getTags: Array[String] = {
        contentDir.listFiles.find(file => {
            file.getName.equals("tags")
        }) match {
            case Some(file) => {
                FileUtils.readFileToString(file).split(",")
            }
            case None => Array()
        }
    }

    private def buildImageContent(file: File) = {
        if (isImageFile(file)) {
            val imageContent = createNewImageContentDirectoryFromImage(file)
            println("Created new ImageContent " + imageContent + " based on image " + file.getAbsolutePath)
            Some(imageContent)
        } else if (file.isDirectory) {
            val imageContent = addImageContentDirectory(file)
            println("Added existing ImageContent " + imageContent + " based on image content dir " + file.getAbsolutePath)
            Some(imageContent)
        } else {
            println("Ignoring unknown file/directory " + file.getAbsolutePath)
            None
        }
    }

    def addImageContentDirectory(directory: File) = {
		val (file, altFiles) = findImageFile(directory)
		val (fileName, fileDate) = getNameAndDateFromFile(file)
		val order = 0
		val imageFile = buildImageFile(file)
        val propertiesFile = findPropertiesFile(directory)
		val properties = parsePropertiesFile(propertiesFile)
        val date = findImageDate(properties, fileDate)
        val name = findName(properties, fileName)
		val imageContent = new ImageContent(directory, name, order, date, properties, imageFile, altFiles)

		(imageContent)
	}

    private def findName(properties: JPropertiesWrapper, fileName:String) = {
        properties.get("name") match {
            case name:Some[String] => name.get
            case None => fileName
        }
    }

    private def findImageDate(properties: JPropertiesWrapper, date: Date) = {
        val format = new SimpleDateFormat("M/d/yyyy")
        properties.get("date") match {
            case dateString:Some[String] =>
                format.parse(dateString.get)
            case None => {
                properties.put("date", format.format(date))
                date
            }
        }
    }

    private def parsePropertiesFile(propertiesFileOpt: Option[File]) = {
        val properties = new Properties()
        propertiesFileOpt match {
            case propertiesFile:Some[File] => {
                properties.load(new FileInputStream(propertiesFile.get))
            }
            case None =>
        }
        new JPropertiesWrapper(properties)
    }

	private def findPropertiesFile(directory: File) = {
		directory.listFiles.find(file => { file.getName.equals("info.properties") })
	}

	private def findImageFile(directory: File) = {

		val altFiles = scala.collection.mutable.HashSet[ImageFile]()
		var imageFile: Option[File] = None

		directory.listFiles.foreach(file => {
			val fileName = getNameWithoutExtensionFromFile(file)
			if (fileName.equals(directory.getName)) {
				imageFile = Some(file)
			} else if (isAltImage(file)) {
				println("adding alt image " + file.getAbsolutePath)
				altFiles += buildImageFile(file)
			}
		})
	
		val file = imageFile.getOrElse(throw new IllegalArgumentException("Could not find image file in " + directory.getAbsolutePath))
		(file, altFiles)
	}

	private def isAltImage(file: File) = {
		val name = file.getName

		name.indexOf(getScaledFileSuffix()) == -1 &&
			name.indexOf(getGrayscaleThumbnailFileSuffix()) == -1 &&
			name.indexOf(getThumbnailFileSuffix()) == -1 &&
			isImageFile(file)
	}

	def createNewImageContentDirectoryFromImage(file: File) = {
		val (name, date) = getNameAndDateFromFile(file)
		val imageDirectory = new File(file.getParentFile, name)
		imageDirectory.mkdirs
		val fileInContentDirectory = new File(imageDirectory, file.getName)
		file.renameTo(fileInContentDirectory)
        addImageContentDirectory(imageDirectory)
	}

	private def getNameAndDateFromFile(file: File) = {
		val name = getNameWithoutExtensionFromFile(file)
		val date = new Date(file.lastModified)
		(name, date)
	}

	private def getNameWithoutExtensionFromFile(file: File) = {
		file.getName.substring(0, file.getName.lastIndexOf("."))
	}

	private def getScaledImageFile(file: File) = {
		val name = getNameWithoutExtensionFromFile(file)
		new File(file.getParentFile, name + getScaledFileSuffix)
	}

	private def buildImageFile(file: File) = {
		var (thumbFile, grayscaleThumbFile) = getThumbnailFiles(file)
		if ( ! thumbFile.exists || ! grayscaleThumbFile.exists ) {
			buildThumbnails(file, thumbFile, grayscaleThumbFile)
		}

		val scaledImageFile = getScaledImageFile(file)
		if ( ! scaledImageFile.exists) {
			buildScaledImageFile(scaledImageFile, file)
		}

		val (width, height) = getDimensions(scaledImageFile)

		ImageFile(width, height, scaledImageFile, thumbFile, grayscaleThumbFile)
	}
}